home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 1 / ETO Development Tools 1.iso / Tools - Objects / MacApp / MacApp 2.0 CD Release / MacApp 2.0 (Many Libraries) / Libraries / UMacApp.TWindow.p < prev    next >
Encoding:
Text File  |  1990-03-27  |  45.8 KB  |  1,689 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UMacApp.TWindow.p }
  4. { Copyright © 1987-1990 by Apple Computer Inc.    All rights reserved. }
  5.  
  6. {--------------------------------------------------------------------------------------------------}
  7. {$S MAClose}
  8.  
  9. PROCEDURE TCloseWindowCommand.DoIt;
  10.  
  11.     BEGIN
  12.     IF fView <> NIL THEN
  13.         TWindow(fView).CloseByUser;
  14.     END;
  15.  
  16. {--------------------------------------------------------------------------------------------------}
  17. {$S MASelCommand}
  18.  
  19. PROCEDURE TCloseWindowCommand.ICloseWindowCommand(itsCmdNumber: CmdNumber;
  20.                                                   itsWindow: TWindow);
  21.  
  22.     BEGIN
  23.     INoChangesCommand(itsCmdNumber, NIL, itsWindow, NIL);
  24.     END;
  25.  
  26. {--------------------------------------------------------------------------------------------------}
  27. {$S MAFields}
  28.  
  29. PROCEDURE TCloseWindowCommand.Fields(PROCEDURE DoToField(fieldName: Str255;
  30.                                                          fieldAddr: Ptr;
  31.                                                          fieldType: integer)); OVERRIDE;
  32.  
  33.     BEGIN
  34.     DoToField('TCloseWindowCommand', NIL, bClass);
  35.  
  36.     INHERITED Fields(DoToField);
  37.     END;
  38.  
  39. {--------------------------------------------------------------------------------------------------}
  40. {$S MAOpen}
  41.  
  42. PROCEDURE TWindow.IWindow(itsDocument: TDocument;
  43.                           itsWMgrWindow: WindowPtr;
  44.                           canResize, canClose, disposeOnFree: BOOLEAN);
  45.  
  46.     VAR
  47.         preDocname:         integer;
  48.         constTitle:         integer;
  49.         aString:            Str255;
  50.         fi:                 FailInfo;
  51.         p:                    Point;
  52.         vp:                 VPoint;
  53.  
  54.     PROCEDURE HandleFailure(error: OSErr;
  55.                             message: LONGINT);
  56.  
  57.         BEGIN
  58.         Free;
  59.         END;
  60.  
  61.     FUNCTION GetSetVPt(v, h: VCoordinate): VPoint;
  62.  
  63.         VAR
  64.             aVPt:                VPoint;
  65.  
  66.         BEGIN
  67.         aVPt.v := v;
  68.         aVPt.h := h;
  69.         GetSetVPt := aVPt;
  70.         END;
  71.  
  72.     BEGIN
  73.     { set up fields necessary to free myself }
  74.     fWMgrWindow := itsWMgrWindow;
  75.     fFreeOnClosing := FALSE;
  76.     fDisposeOnFree := disposeOnFree;
  77.  
  78.     SetPort(GetGrafPort);                                { ??? Why is this necessary? }
  79.     WITH fWMgrWindow^.portRect DO
  80.         BEGIN
  81.         p := topleft;
  82.         LocalToGlobal(p);
  83.         PtToVPt(p, vp);
  84.         IView(itsDocument, NIL, vp, GetSetVPt(bottom - top, right - left), SizeVariable,
  85.               SizeVariable);
  86.         END;
  87.  
  88.     fProcID := GetWRefCon(itsWMgrWindow);
  89.     SetWRefcon(itsWMgrWindow, LONGINT(SELF));
  90.  
  91.     fAdapted := FALSE;                                    { Set by AdaptToScreen }
  92.     fHorzCentered := FALSE;                             { Set by Center }
  93.     fVertCentered := FALSE;                             { Set by Center }
  94.     fStaggered := FALSE;                                { Set by SimpleStagger }
  95.     fForcedOnScreen := FALSE;                            { Set by ForceOnScreen }
  96.  
  97.     { We can't tell if any changing will be required so we just set these false here.
  98.     If the developer sets them true then we respect them or if the developer calls the
  99.     corresponding functions we set them. }
  100.     fMustAdapt := FALSE;
  101.     fMustHorzCenter := FALSE;
  102.     fMustVertCenter := FALSE;
  103.     fMustStagger := FALSE;
  104.     fMustForceOnScreen := FALSE;
  105.  
  106.     fIsActive := FALSE;
  107.     fIsResizable := canResize;
  108.     fIsClosable := canClose;
  109.     fTarget := SELF;
  110.     fTargetID := fIdentifier;
  111.     fClosesDocument := TRUE;
  112.     fOpenInitially := TRUE;
  113.     fIsModal := FALSE;
  114.     fDoFirstClick := FALSE;
  115.     fFloats := FALSE;
  116.     IF BuildWindowRgns(BuildWindowRgns(kBuild)) THEN;    { sets fContRgnInset & fContDifference }
  117.  
  118.     CatchFailures(fi, HandleFailure);
  119.  
  120.     fMoveBounds := gStdWMoveBounds;
  121.     SetResizeLimits(gStdWSizeRect.topleft, gStdWSizeRect.botRight);
  122.     GetTitle(aString);
  123.     IF ParseTitleTemplate(aString, preDocname, constTitle) THEN
  124.         SetWTitle(itsWMgrWindow, aString);
  125.     fPreDocname := preDocname;
  126.     fConstTitle := constTitle;
  127.  
  128.     InstallDocument(itsDocument);
  129.  
  130.     Success(fi);
  131.     END;
  132.  
  133. {--------------------------------------------------------------------------------------------------}
  134. {$S MAOpen}
  135.  
  136. PROCEDURE TWindow.IRes(itsDocument: TDocument;
  137.                        itsSuperView: TView;
  138.                        VAR itsParams: Ptr);
  139.  
  140.     VAR
  141.         bounds:             Rect;
  142.         aWMgrWindow:        WindowPtr;
  143.         preDocname:         integer;
  144.         constTitle:         integer;
  145.         aString:            Str255;
  146.         fi:                 FailInfo;
  147.  
  148.     PROCEDURE HandleFailure(error: OSErr;
  149.                             message: LONGINT);
  150.  
  151.         BEGIN
  152.         Free;
  153.         END;
  154.  
  155.     BEGIN
  156.     { set up fields necessary to free myself }
  157.     fWMgrWindow := NIL;
  158.     fFreeOnClosing := FALSE;
  159.     fDisposeOnFree := TRUE;
  160.  
  161.     INHERITED IRes(itsDocument, itsSuperView, itsParams);
  162.  
  163.     SetRect(bounds, fLocation.h, fLocation.v, fLocation.h + fSize.h, fLocation.v + fSize.v);
  164.  
  165.     WITH WindowTemplatePtr(itsParams)^ DO
  166.         BEGIN
  167.         CatchFailures(fi, HandleFailure);
  168.  
  169.         fProcID := procID;
  170.  
  171.         IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  172.             aWMgrWindow := WindowPtr(NewCWindow(NIL, bounds, title, FALSE, procID, Pointer( - 1),
  173.                                                 hasGoAway, ORD4(SELF)))
  174.         ELSE
  175.             aWMgrWindow := NewWindow(NIL, bounds, title, FALSE, procID, Pointer( - 1), hasGoAway,
  176.                                      ORD4(SELF));
  177.         fWMgrWindow := aWMgrWindow;
  178.  
  179.         fAdapted := FALSE;                                { Set by AdaptToScreen }
  180.         fHorzCentered := FALSE;                         { Set by Center }
  181.         fVertCentered := FALSE;                         { Set by Center }
  182.         fStaggered := FALSE;                            { Set by SimpleStagger }
  183.         fForcedOnScreen := FALSE;                        { Set by ForceOnScreen }
  184.         fIsActive := FALSE;
  185.         fIsResizable := resizable;
  186.         fIsClosable := hasGoAway;
  187.         fTarget := SELF;
  188.         fTargetID := targetID;
  189.         fIsModal := isModal;
  190.         fDoFirstClick := doFirstClick;
  191.         fFreeOnClosing := freeOnClosing;
  192.         fDisposeOnFree := disposeOnFree;
  193.         fClosesDocument := closesDocument;
  194.         fOpenInitially := openInitially;
  195.         fMoveBounds := gStdWMoveBounds;
  196.         SetResizeLimits(gStdWSizeRect.topleft, gStdWSizeRect.botRight);
  197.         fFloats := FALSE;
  198.         IF BuildWindowRgns(BuildWindowRgns(kBuild)) THEN; { sets fContRgnInset & fContDifference }
  199.  
  200.         GetTitle(aString);
  201.         IF ParseTitleTemplate(aString, preDocname, constTitle) THEN
  202.             SetWTitle(aWMgrWindow, aString);
  203.         fPreDocname := preDocname;
  204.         fConstTitle := constTitle;
  205.  
  206.         InstallDocument(itsDocument);
  207.  
  208.         Success(fi);
  209.  
  210.         fMustAdapt := mustAdaptToScreen;
  211.         fMustHorzCenter := horzCenter;
  212.         fMustVertCenter := vertCenter;
  213.         fMustStagger := stagger;
  214.         fMustForceOnScreen := mustForceOnScreen;
  215.  
  216.         OffsetPtrWStr(itsParams, SIZEOF(WindowTemplate));
  217.         END;
  218.     END;
  219.  
  220. {--------------------------------------------------------------------------------------------------}
  221. {$S MAWriteRes}
  222.  
  223. PROCEDURE TWindow.WRes(theResource: ViewRsrcHandle;
  224.                        VAR itsParams: Ptr); OVERRIDE;
  225.  
  226.     VAR
  227.         theTitle:            Str255;
  228.         wnPtr:                WindowTemplatePtr;
  229.  
  230.     BEGIN
  231.     INHERITED WRes(theResource, itsParams);
  232.  
  233.     GetTitle(theTitle);
  234.  
  235.     wnPtr := WindowTemplatePtr(ExpandPtrWStr(theResource, itsParams, SIZEOF(WindowTemplate),
  236.                                              LENGTH(theTitle)));
  237.  
  238.     WITH wnPtr^ DO
  239.         BEGIN
  240.         procID := fProcID;
  241.         hasGoAway := fIsClosable;
  242.         resizable := fIsResizable;
  243.         isModal := fIsModal;
  244.         doFirstClick := fDoFirstClick;
  245.         freeOnClosing := fFreeOnClosing;
  246.         disposeOnFree := fDisposeOnFree;
  247.         closesDocument := fClosesDocument;
  248.         openInitially := fOpenInitially;
  249.         mustAdaptToScreen := fMustAdapt;
  250.         stagger := fMustStagger;
  251.         mustForceOnScreen := fMustForceOnScreen;
  252.         vertCenter := fMustVertCenter;
  253.         horzCenter := fMustHorzCenter;
  254.         targetID := fTargetID;
  255.         CopyStr255(theTitle, PRStr(title));
  256.         END;
  257.     END;
  258.  
  259. {--------------------------------------------------------------------------------------------------}
  260. {$S MAWriteRes}
  261.  
  262. PROCEDURE TWindow.WriteRes(theResource: ViewRsrcHandle;
  263.                            VAR itsParams: Ptr); OVERRIDE;
  264.  
  265.     BEGIN
  266.     gWResSignature := 'wind'; gWResType := 'TWindow';
  267.     WRes(theResource, itsParams);
  268.     END;
  269.  
  270. {--------------------------------------------------------------------------------------------------}
  271. {$S MAClose}
  272.  
  273. PROCEDURE TWindow.Free; OVERRIDE;
  274.  
  275.     VAR
  276.         disposeOnFree:        BOOLEAN;
  277.         wmgrWindow:         WindowPtr;
  278.  
  279.     BEGIN
  280.     disposeOnFree := fDisposeOnFree;
  281.     wmgrWindow := fWMgrWindow;
  282.     fWMgrWindow := NIL;                                 { ??? will this help? }
  283.  
  284.     IF fDocument <> NIL THEN
  285.         fDocument.DeleteWindow(SELF)
  286.     ELSE
  287.         gApplication.DeleteFreeWindow(SELF);
  288.  
  289.     INHERITED Free;
  290.  
  291.     { ****** DON'T REFER TO ANY FIELDS OR METHODS OF SELF ****** }
  292.  
  293.     wmgrWindow := FreeIfWMgrWindow(wmgrWindow, disposeOnFree);
  294.     END;
  295.  
  296. {--------------------------------------------------------------------------------------------------}
  297. {$S MAActivate}
  298.  
  299. PROCEDURE TWindow.Activate(entering: BOOLEAN);
  300.  
  301.     VAR
  302.         different:            BOOLEAN;
  303.         aWindow:            TWindow;
  304.  
  305.     BEGIN
  306.     InvalidateFocus;                                    { Must refocus to make sure thePort is set }
  307.     different := entering <> fIsActive;
  308.  
  309.     IF different THEN
  310.         BEGIN
  311.         Update;                                         { Logically the order is wrong, but it gives
  312.                                                          the correct visual effect. ??? Revisit? }
  313.         INHERITED Activate(entering);
  314.  
  315.         IF entering THEN
  316.             BEGIN
  317.             aWindow := gApplication.GetActiveWindow;
  318.             IF aWindow <> NIL THEN                        { So lost deactivate doesn't screw up
  319.                                                          gTarget }
  320.                 aWindow.Activate(FALSE);
  321.             fIsActive := entering;
  322.             gApplication.SetTarget(fTarget);
  323.             END
  324.         ELSE
  325.             BEGIN
  326.             fIsActive := entering;
  327.             gApplication.SetTarget(gApplication);
  328.             SetCursor(arrow);                            { ensure that the cursor is an arrow when
  329.                                                          MacApp loses control }
  330.             END;
  331.         END;
  332.  
  333.     IF fIsResizable & Focus & IsVisible THEN
  334.         DrawResizeIcon;
  335.  
  336.     END;
  337.  
  338. {--------------------------------------------------------------------------------------------------}
  339. {$S MAOpen}
  340.  
  341. PROCEDURE TWindow.AdaptToScreen;
  342.  
  343.     CONST
  344.         stdHScreen            = 512;
  345.         stdVScreen            = 342;
  346.         stdScreen            = $10000 * stdVScreen + stdHScreen;
  347.  
  348.     VAR
  349.         diff:                Point;
  350.         windRect:            Rect;
  351.         newSize:            Point;
  352.         theLimits:            Rect;
  353.  
  354.     BEGIN
  355.     fAdapted := TRUE;                                    { We adapted to the screen }
  356.     { Compute difference between current screen and std Mac screen }
  357.     diff := screenBits.bounds.botRight;
  358.     SubPt(screenBits.bounds.topleft, diff);
  359.     SubPt(Point(stdScreen), diff);
  360.     GetGlobalBounds(windRect);
  361.  
  362.     { If screen is larger, enlarge the window. If the window is too large, shrink it }
  363.     IF (LONGINT(diff) <> 0) | (windRect.bottom > screenBits.bounds.bottom) | { do an adjustment for
  364.            larger screen }
  365.        (windRect.right > screenBits.bounds.right) THEN
  366.         BEGIN
  367.         newSize := windRect.botRight;
  368.         AddPt(diff, newSize);                            { the window adapted to the new screen size
  369.                                                          }
  370.         theLimits := fResizeLimits;
  371.         WITH theLimits DO
  372.             BEGIN
  373.             { Consider the location of the window, bound it by the resize limits }
  374.             newSize.v := MinMax(top, newSize.v - windRect.top, bottom);
  375.             newSize.h := MinMax(left, newSize.h - windRect.left, right);
  376.             END;
  377.  
  378.         Resize(newSize.h, newSize.v, kInvalidate);
  379.  
  380.         END;
  381.     END;
  382.  
  383. {--------------------------------------------------------------------------------------------------}
  384. {$S MAWindowRes}
  385.  
  386. FUNCTION TWindow.AllowsMenuAccess: BOOLEAN;
  387.  
  388.     BEGIN
  389.     { Default is to always allow menu access, even if modal }
  390.     AllowsMenuAccess := TRUE;
  391.     END;
  392.  
  393. {--------------------------------------------------------------------------------------------------}
  394. {$S MANonRes}
  395.  
  396. FUNCTION GetAndLoadWDefProc(windowDefProc: Handle): Handle;
  397. { utility routine: given a windowDefProc, this routine returns its actual address and loads it }
  398.  
  399.     VAR
  400.         wDefProc:            Handle;
  401.  
  402.     BEGIN
  403.     wDefProc := Handle(StripLong(windowDefProc));
  404.     IF wDefProc^ = NIL THEN
  405.         LoadResource(wDefProc);
  406.     GetAndLoadWDefProc := wDefProc;
  407.     END;
  408.  
  409. {--------------------------------------------------------------------------------------------------}
  410. {$S MANonRes}
  411.  
  412. FUNCTION GetWindowVariant(theWindow: WindowPtr): integer;
  413. { given a windowPtr, this routine returns its variant }
  414.  
  415.     BEGIN
  416.     IF TrapExists(_GetWVariant) THEN
  417.         GetWindowVariant := GetWVariant(theWindow)
  418.     ELSE
  419.         GetWindowVariant := BAND($0F, BSR(LONGINT(WindowPeek(theWindow)^.windowDefProc), 24));
  420.     END;
  421.  
  422. {--------------------------------------------------------------------------------------------------}
  423.  
  424. FUNCTION CallWDefProc(varCode: integer;
  425.                       theWindow: WindowPtr;
  426.                       message: integer;
  427.                       param: LONGINT;
  428.                       wDefProc: UNIV Handle): LONGINT;
  429.     INLINE $205F,                                        { MOVE.L (A7)+,A0 }
  430.            $2050,                                        { MOVE.L (A0),A0 }
  431.            $4E90;                                        { JSR (A0) }
  432.  
  433. {--------------------------------------------------------------------------------------------------}
  434. {$S MAOpen}
  435.  
  436. PROCEDURE TWindow.Center(horizontally, vertically, forDialog: BOOLEAN);
  437.  
  438.     VAR
  439.         windowSize:         Point;
  440.         screenSize:         Point;
  441.         contentSize:        Point;
  442.         bottomRightInset:    Point;
  443.         globalbounds, screenRect: Rect;
  444.         rgnsWereBuilt:        BOOLEAN;
  445.  
  446.     BEGIN
  447.     fHorzCentered := horizontally;
  448.     fVertCentered := vertically;
  449.     IF (fWMgrWindow <> NIL) & (horizontally | vertically) THEN
  450.         BEGIN
  451.         IF GetMaxIntersectedDevice(screenRect) = NIL THEN; { don't care about result }
  452.         WITH screenRect DO
  453.             BEGIN
  454.             screenSize.h := right - left;
  455.             screenSize.v := bottom - top;                { NOTE: GetMaxIntersectedDevice accounts for
  456.                                                          menubar so don't subtract gMbarHeight }
  457.             END;
  458.  
  459.         WITH WindowPeek(fWMgrWindow)^ DO
  460.             BEGIN
  461.             rgnsWereBuilt := BuildWindowRgns(kBuild);
  462.             WITH strucRgn^^.rgnBBox DO
  463.                 BEGIN
  464.                 windowSize.h := right - left;
  465.                 windowSize.v := bottom - top;
  466.                 END;
  467.             IF BuildWindowRgns(rgnsWereBuilt) THEN;     { discard result }
  468.  
  469.             GetGlobalBounds(globalbounds);
  470.             WITH globalbounds DO
  471.                 BEGIN
  472.                 contentSize.h := right - left;
  473.                 contentSize.v := bottom - top;
  474.                 END;
  475.  
  476.             { The top-left content inset isn't enough; factor in the amount to the right of the }
  477.             { content also. }
  478.             bottomRightInset := windowSize;
  479.             SubPt(contentSize, bottomRightInset);
  480.             SubPt(fContRgnInset, bottomRightInset);
  481.             {$PUSH} {$H-}
  482.             SubPt(bottomRightInset, fContRgnInset);
  483.             {$POP}
  484.             END;
  485.  
  486.         WITH globalbounds DO
  487.             BEGIN
  488.             IF horizontally THEN
  489.                 left := (screenSize.h - contentSize.h + fContRgnInset.h) DIV 2;
  490.             IF vertically THEN
  491.                 IF forDialog THEN
  492.                 { Put it in the top third of the screen }
  493.                     top := ((screenSize.v - contentSize.v + fContRgnInset.v) DIV 3) + 20
  494.                 ELSE
  495.                     top := ((screenSize.v - contentSize.v + fContRgnInset.v) DIV 2) + 20;
  496.             END;
  497.         Locate(globalbounds.left, globalbounds.top, kDontInvalidate);
  498.         END;
  499.     END;
  500.  
  501. {--------------------------------------------------------------------------------------------------}
  502. {$S MAClose}
  503.  
  504. PROCEDURE TWindow.Close; OVERRIDE;
  505.  
  506.     BEGIN
  507.     INHERITED Close;
  508.  
  509.     Show(FALSE, kRedraw);
  510.     Activate(FALSE);                                    { ??? Is this necessary? }
  511.  
  512.     IF fFreeOnClosing THEN
  513.         Free;
  514.     END;
  515.  
  516. {--------------------------------------------------------------------------------------------------}
  517. {$S MAClose}
  518.  
  519. PROCEDURE TWindow.CloseByUser;
  520.  
  521.     BEGIN
  522.     IF fDocument = NIL THEN                             { free window }
  523.         Close
  524.     ELSE
  525.         fDocument.CloseView(SELF);
  526.     END;
  527.  
  528. {--------------------------------------------------------------------------------------------------}
  529. {$S MASelCommand}
  530.  
  531. FUNCTION TWindow.DoMenuCommand(aCmdNumber: CmdNumber): TCommand; OVERRIDE;
  532.  
  533.     VAR
  534.         aCloseWindowCommand: TCloseWindowCommand;
  535.         oldObjectPerm:        BOOLEAN;
  536.  
  537.     BEGIN
  538.     DoMenuCommand := NIL;
  539.  
  540.     CASE aCmdNumber OF
  541.         cClose:
  542.             BEGIN
  543.             oldObjectPerm := AllocateObjectsFromPerm(FALSE); { Guarantee the allocation }
  544.             New(aCloseWindowCommand);
  545.             IF AllocateObjectsFromPerm(oldObjectPerm) THEN;
  546.  
  547.             FailNil(aCloseWindowCommand);                { just in case }
  548.             aCloseWindowCommand.ICloseWindowCommand(aCmdNumber, SELF);
  549.             DoMenuCommand := aCloseWindowCommand;
  550.             END;
  551.         OTHERWISE
  552.             DoMenuCommand := INHERITED DoMenuCommand(aCmdNumber);
  553.     END;
  554.  
  555.     END;
  556.  
  557. {--------------------------------------------------------------------------------------------------}
  558. {$S MAWindowRes}
  559.  
  560. PROCEDURE TWindow.DoSetupMenus; OVERRIDE;
  561.  
  562.     BEGIN
  563.     IF NOT fIsModal THEN                                { Don't enable menu/app commands if modal }
  564.         BEGIN
  565.         Enable(cClose, fIsClosable);                    { window objects take care of themselves! }
  566.  
  567.         INHERITED DoSetupMenus;
  568.         END;
  569.     END;
  570.  
  571. {--------------------------------------------------------------------------------------------------}
  572. {$S MAWindowRes}
  573.  
  574. PROCEDURE TWindow.DrawContents; OVERRIDE;
  575.  
  576.     VAR
  577.         visRect:            Rect;
  578.         {$IFC qExperimentalAndUnsupported}
  579.         fi:                    FailInfo;
  580.         oldgEnableDoubleBuffering: Boolean;
  581.         {$EndC}
  582.  
  583.     PROCEDURE HdlDrawContents(error: OSErr;
  584.                               message: LONGINT);
  585.     
  586.         BEGIN
  587.         {$IFC qExperimentalAndUnsupported}
  588.         gEnableDoubleBuffering := oldgEnableDoubleBuffering;
  589.         {$EndC}
  590.         END;
  591.     
  592.     PROCEDURE DoDrawContents;
  593.     
  594.         VAR
  595.             visRect:            Rect;
  596.     
  597.         BEGIN
  598.         IF Focus THEN
  599.             BEGIN
  600.             { Ensure that the background is correct }
  601.             GetVisibleRect(visRect);
  602.             EraseRect(visRect);
  603.     
  604.             INHERITED DrawContents;
  605.     
  606.             { Draw the resize icon last so other views don't munch it.
  607.             ??? Should the resize icon be a subview that is always drawn last?}
  608.             IF fIsResizable THEN
  609.                 DrawResizeIcon;
  610.             END;
  611.         END;
  612.  
  613.     BEGIN
  614.     {$IFC qExperimentalAndUnsupported}
  615.     IF Focus & IsVisible THEN
  616.         BEGIN
  617.         IF gEnableDoubleBuffering & NOT (gPrinting | gDrawingPictScrap) THEN
  618.             BEGIN
  619.             oldgEnableDoubleBuffering := gEnableDoubleBuffering;
  620.             gEnableDoubleBuffering := FALSE;            { so subviews won't attempt to do off screen
  621.                                                          }
  622.             CatchFailures(fi, HdlDrawContents);
  623.             DoOffScreen(DoDrawContents);
  624.             Success(fi);
  625.             gEnableDoubleBuffering := oldgEnableDoubleBuffering;
  626.             END
  627.         ELSE
  628.             DoDrawContents;
  629.         END;
  630.     {$ELSEC}
  631.     DoDrawContents;
  632.     {$EndC}
  633.     END;
  634.  
  635. {--------------------------------------------------------------------------------------------------}
  636. {$S MAWindowRes}
  637.  
  638. PROCEDURE TWindow.DrawResizeIcon;
  639.  
  640.     VAR
  641.         r:                    Rect;
  642.  
  643.     BEGIN
  644.     IF qDebug THEN
  645.         AssumeFocused;
  646.  
  647.     GetQDExtent(r);
  648.     r.left := r.right - kSBarSizeMinus1;
  649.     r.top := r.bottom - kSBarSizeMinus1;
  650.  
  651.     {$IFC qDebug}
  652.     UseTempRgn('TWindow.DrawResizeIcon');
  653.     {$ENDC}
  654.  
  655.     GetClip(gTempRgn);
  656.     ClipRect(r);
  657.     PenNormal;
  658.     DrawGrowIcon(fWMgrWindow);
  659.     SetClip(gTempRgn);
  660.  
  661.     {$IFC qDebug}
  662.     DoneWithTempRgn;
  663.     {$ENDC}
  664.     END;
  665.  
  666. {--------------------------------------------------------------------------------------------------}
  667. {$S MAWindowRes}
  668.  
  669. FUNCTION TWindow.Focus: BOOLEAN; OVERRIDE;
  670.  
  671. {$IFC qDebug OR qExperimentalAndUnsupported}
  672.  
  673.     VAR
  674.         {$EndC}
  675.         {$IFC qDebug}
  676.         currentPort:        GrafPtr;
  677.         {$ENDC}
  678.         {$IFC qExperimentalAndUnsupported}
  679.         aFocusRec:            FocusRec;
  680.         {$EndC}
  681.  
  682.     BEGIN
  683.     Focus := TRUE;                                        { Hope for the best }
  684.  
  685.     IF IsFocused THEN
  686.         BEGIN
  687.         {$IFC qDebug}
  688.         IF LONGINT(GetGrafPort^.portRect.topleft) <> 0 THEN
  689.             ProgramBreak('TWindow.Focus: Origin is not (0,0)');
  690.  
  691.         GetPort(currentPort);
  692.         IF currentPort <> GetGrafPort THEN
  693.             BEGIN
  694.             ProgramBreak('TWindow.Focus: Port is incorrect');
  695.             Focus := FALSE
  696.             END;
  697.         {$ENDC}
  698.         Exit(Focus);
  699.         END;
  700.  
  701.     {$IFC qExperimentalAndUnsupported}
  702.     IF fFocusRec.IsValid THEN
  703.         BEGIN
  704.         aFocusRec := fFocusRec;
  705.         SetFocus(aFocusRec);
  706.         Exit(Focus);
  707.         END;
  708.     {$EndC}
  709.  
  710.     IF (gDrawingPictScrapView = SELF) | ((gCurrPrintHandler <> NIL) & (gCurrPrintHandler.fView =
  711.        SELF)) THEN
  712.         BEGIN
  713.         { GrafPort has been supplied }
  714.         gFocusedView := SELF;
  715.         END
  716.  
  717.     ELSE IF fWMgrWindow <> NIL THEN
  718.         BEGIN
  719.         SetPort(GetGrafPort);
  720.         SetOrigin(0, 0);
  721.         gLongOffset := gZeroVPt;
  722.         SetClip(thePort^.visRgn);
  723.         gFocusedView := SELF;
  724.  
  725.         {$IFC qExperimentalAndUnsupported}
  726.         aFocusRec.clip := fFocusRec.clip;
  727.         GetFocus(aFocusRec);
  728.         fFocusRec := aFocusRec;
  729.         {$EndC}
  730.         END
  731.     ELSE
  732.         BEGIN
  733.         { If we get this far, then we can't focus }
  734.         ClipRect(gZeroRect);
  735.         InvalidateFocus;
  736.         Focus := FALSE;
  737.         END;
  738.     END;
  739.  
  740. {--------------------------------------------------------------------------------------------------}
  741. {$S MAWindowRes}
  742.  
  743. FUNCTION TWindow.FocusOnSuperView: BOOLEAN; OVERRIDE;
  744.  
  745.     BEGIN
  746.     FocusOnSuperView := FALSE;
  747.     END;
  748.  
  749. {--------------------------------------------------------------------------------------------------}
  750. {$S MAOpen}
  751.  
  752. PROCEDURE TWindow.ForceOnScreen;
  753.  
  754. { ForceOnScreen guarantees that some minimal drag area is accessible to the user, to be dragged
  755.   to the desired location. }
  756.  
  757.     CONST
  758.         kMinDragArea        = 4;                        { ??? should this be settable? }
  759.  
  760.     VAR
  761.         global:             Rect;
  762.         deltaH:             integer;
  763.         deltaV:             integer;
  764.         aTempRgn:            RgnHandle;
  765.         rgnsWereBuilt:        BOOLEAN;
  766.  
  767.     PROCEDURE AdjustGlobalBounds(VAR boundsToAdjust: Rect);
  768.     { assume "boundsToAdjust" is set to the window bounds in global coordinates }
  769.  
  770.         VAR
  771.             visScreenRect:        Rect;
  772.  
  773.         BEGIN
  774.         { since we don't _really_ know what the drag rgn is, we'll assume that moving the topleft
  775.           pt of the window on screen is sufficient to make it draggable, so calculate the deltas
  776.           necessary to move the topleft pt into visible screen rect }
  777.  
  778.         IF GetMaxIntersectedDevice(visScreenRect) = NIL THEN; { NOTE: uses gTempRgn }
  779.         InsetRect(visScreenRect, kMinDragArea, kMinDragArea);
  780.         WITH visScreenRect DO
  781.             BEGIN
  782.             IF boundsToAdjust.top < top THEN
  783.                 deltaV := top - boundsToAdjust.top + fContRgnInset.v
  784.             ELSE IF boundsToAdjust.top > bottom THEN
  785.                 deltaV := bottom - boundsToAdjust.top - fContRgnInset.v;
  786.  
  787.             IF boundsToAdjust.left < left THEN
  788.                 deltaH := left - boundsToAdjust.left + fContRgnInset.h
  789.             ELSE IF boundsToAdjust.left > right THEN
  790.                 deltaH := right - boundsToAdjust.right - fContRgnInset.h;
  791.             END;
  792.         END;
  793.  
  794.     BEGIN
  795.     fForcedOnScreen := TRUE;
  796.  
  797.     deltaH := 0;
  798.     deltaV := 0;
  799.  
  800.         { On many systems (including Color QD & the Radius FPD), it's possible to have a
  801.         non-rectangular desktop.    Try to be nice to people who saved windows
  802.         on secondary screens.  GrayRgn is the true indicator of the shape
  803.         of the desktop--screenBits.bounds is the size of the screen with the
  804.         menu bar on it. }
  805.  
  806.     {$IFC qDebug}
  807.     UseTempRgn('ForceOnScreen');
  808.     {$ENDC}
  809.  
  810.     rgnsWereBuilt := BuildWindowRgns(kBuild);
  811.     WITH WindowPeek(fWMgrWindow)^ DO
  812.         BEGIN
  813.         DiffRgn(strucRgn, contRgn, gTempRgn);            { strucRgn less contRgn ≈≈ drag rgn }
  814.         IF EmptyRgn(gTempRgn) THEN
  815.             CopyRgn(strucRgn, gTempRgn);                { at least get the strucRgn }
  816.         END;                                            { WITH WindowPeek(fWMgrWindow)^ }
  817.     IF BuildWindowRgns(rgnsWereBuilt) THEN;             { discard result }
  818.  
  819.     { get the desktop rgn, inset by a minimal drag area }
  820.     aTempRgn := MakeNewRgn;
  821.     CopyRgn(GetGrayRgn, aTempRgn);                        { aTempRgn := desktop rgn }
  822.     InsetRgn(aTempRgn, kMinDragArea, kMinDragArea);     { inset aTempRgn }
  823.     SectRgn(gTempRgn, aTempRgn, aTempRgn);                { do drag rgn & desktop rgn instersect ? }
  824.     {$IFC qDebug}
  825.     DoneWithTempRgn;                                    { (AdjustGlobalBounds needs gTempRgn) }
  826.     {$ENDC}
  827.  
  828.     GetGlobalBounds(global);
  829.  
  830.     IF EmptyRgn(aTempRgn) | NOT IsDraggable(aTempRgn^^.rgnBBox) THEN
  831.         AdjustGlobalBounds(global);                     { no => adjust the window's global bounds }
  832.     DisposeRgn(aTempRgn);
  833.     OffsetRect(global, deltaH, deltaV);
  834.     WITH global DO
  835.         Locate(left, top, kDontInvalidate);
  836.     END;
  837.  
  838. {--------------------------------------------------------------------------------------------------}
  839. {$S MAWindowRes}
  840.  
  841. PROCEDURE TWindow.GetGlobalBounds(VAR globalbounds: Rect);
  842.  
  843.     VAR
  844.         savedPort:            GrafPtr;
  845.  
  846.     BEGIN
  847.     IF fWMgrWindow = NIL THEN
  848.         globalbounds := gZeroRect                        { CSK 89.11.30 }
  849.     ELSE
  850.         BEGIN
  851.         GetPort(savedPort);
  852.         SetPort(GetGrafPort);
  853.         globalbounds := GetGrafPort^.portRect;
  854.         LocalToGlobal(globalbounds.topleft);
  855.         LocalToGlobal(globalbounds.botRight);
  856.         SetPort(savedPort);
  857.         END;
  858.     END;
  859.  
  860. {--------------------------------------------------------------------------------------------------}
  861. {$S MANonRes}
  862.  
  863. FUNCTION TWindow.GetMaxIntersectedDevice(VAR screenRect: Rect): GDHandle;
  864.  
  865.     PROCEDURE CalcScreenRect;
  866.  
  867.         VAR
  868.             aGDHandle, maxSectGD: GDHandle;
  869.             globalStrucRect, aGDScreenRect: Rect;
  870.             gdSectRect, dontCare: Rect;
  871.             sectArea:            LONGINT;
  872.             maxSectArea:        LONGINT;
  873.             moveBounds:         Rect;
  874.             rgnsWereBuilt:        BOOLEAN;
  875.  
  876.         BEGIN
  877.         rgnsWereBuilt := BuildWindowRgns(kBuild);        { sets fContRgnInset & fContDifference, and
  878.                                                          make sure contrgn and strucrgn are
  879.                                                          available }
  880.         globalStrucRect := WindowPeek(fWMgrWindow)^.strucRgn^^.rgnBBox;
  881.         IF BuildWindowRgns(rgnsWereBuilt) THEN;         { discard result }
  882.  
  883.         moveBounds := fMoveBounds;
  884.  
  885.         aGDHandle := GetDeviceList;
  886.         maxSectGD := GetMainDevice;                     { set as best choice default }
  887.         maxSectArea := 0;
  888.         REPEAT                                            { calc which scrn intersects largest part of
  889.                                                          window }
  890.             BEGIN
  891.             aGDScreenRect := aGDHandle^^.gdRect;
  892.             IF SectRect(aGDScreenRect, moveBounds, dontCare) & SectRect(globalStrucRect,
  893.                                                                         aGDScreenRect,
  894.                gdSectRect) THEN
  895.                 BEGIN
  896.                 WITH gdSectRect DO
  897.                     sectArea := IntMultiply(bottom - top, right - left);
  898.                 IF sectArea > maxSectArea THEN            { do we have a new winner? }
  899.                     BEGIN
  900.                     maxSectArea := sectArea;
  901.                     maxSectGD := aGDHandle;
  902.                     END;
  903.                 END;
  904.             aGDHandle := GetNextDevice(aGDHandle);
  905.             END;
  906.         UNTIL aGDHandle = NIL;
  907.  
  908.         IF maxSectGD <> GetMainDevice THEN
  909.             screenRect := maxSectGD^^.gdRect
  910.         ELSE
  911.             BEGIN                                        { Account for menu bar on the main screen.
  912.                                                          Don't just assume that its at the top of
  913.                                                          the screen! }
  914.             {$IFC qDebug}
  915.             UseTempRgn('TWindow.GetMaxIntersectedDevice');
  916.             {$ENDC}
  917.             RectRgn(gTempRgn, maxSectGD^^.gdRect);        { main screen with menubar }
  918.             SectRgn(gTempRgn, GetGrayRgn, gTempRgn);    { GetGrayRgn = desktop rgn w/o menubar }
  919.             screenRect := gTempRgn^^.rgnBBox;            { => main screen w/o menubar }
  920.             {$IFC qDebug}
  921.             DoneWithTempRgn;
  922.             {$ENDC}
  923.             END;
  924.         GetMaxIntersectedDevice := maxSectGD;
  925.         END;
  926.  
  927.     BEGIN
  928.     IF qNeedsColorQD | gConfiguration.hasColorQD THEN
  929.         CalcScreenRect
  930.     ELSE
  931.         BEGIN                                            { Account for menu bar on the main screen.
  932.                                                          Don't just assume that its at the top of
  933.                                                          the screen! }
  934.         GetMaxIntersectedDevice := NIL;                 { we only have GDHandle in CQD world }
  935.         {$IFC qDebug}
  936.         UseTempRgn('TWindow.GetMaxIntersectedDevice');
  937.         {$ENDC}
  938.         RectRgn(gTempRgn, screenBits.bounds);            { main screen with menubar }
  939.         SectRgn(gTempRgn, GetGrayRgn, gTempRgn);        { GetGrayRgn = desktop rgn w/o menubar }
  940.         screenRect := gTempRgn^^.rgnBBox;                { => main screen w/o menubar }
  941.         {$IFC qDebug}
  942.         DoneWithTempRgn;
  943.         {$ENDC}
  944.         END;
  945.     END;
  946.  
  947. {--------------------------------------------------------------------------------------------------}
  948. {$S MAInspector}
  949.  
  950. PROCEDURE TWindow.GetInspectorName(VAR inspectorName: Str255); OVERRIDE;
  951.  
  952.     BEGIN
  953.     IF (fWMgrWindow <> NIL) & (NOT ODD(ORD4(fWMgrWindow))) THEN
  954.         GetTitle(inspectorName);
  955.     END;
  956.  
  957. {--------------------------------------------------------------------------------------------------}
  958. {$S MAWindowRes}
  959.  
  960. FUNCTION TWindow.GetGrafPort: GrafPtr; OVERRIDE;
  961.  
  962.     BEGIN
  963.     IF gPrinting | gDrawingPictScrap THEN
  964.         GetGrafPort := thePort                            {thePort assumed to be set by print handler}
  965.     ELSE IF fWMgrWindow <> NIL THEN
  966.         GetGrafPort := GrafPtr(fWMgrWindow)
  967.     ELSE
  968.         GetGrafPort := NIL;
  969.     END;
  970.  
  971. {--------------------------------------------------------------------------------------------------}
  972. {$S MAWindowRes}
  973.  
  974. PROCEDURE TWindow.GetTitle(VAR theTitle: Str255);
  975.  
  976.     BEGIN
  977.     GetWTitle(fWMgrWindow, theTitle);
  978.     END;
  979.  
  980. {--------------------------------------------------------------------------------------------------}
  981. {$S MAWindowRes}
  982.  
  983. FUNCTION TWindow.GetWindow: TWindow; OVERRIDE;
  984.  
  985.     BEGIN
  986.     GetWindow := SELF;
  987.     END;
  988.  
  989. {--------------------------------------------------------------------------------------------------}
  990. {$S MAClose}
  991.  
  992. PROCEDURE TWindow.GoAwayByUser(globalMouse: Point);
  993.  
  994.     VAR
  995.         aCloseWindowCommand: TCloseWindowCommand;
  996.         oldObjectPerm:        BOOLEAN;
  997.  
  998.     BEGIN
  999.     IF fIsClosable & TrackGoAway(fWMgrWindow, globalMouse) THEN
  1000.         BEGIN
  1001.         oldObjectPerm := AllocateObjectsFromPerm(FALSE); { Guarantee the allocation }
  1002.         New(aCloseWindowCommand);
  1003.         IF AllocateObjectsFromPerm(oldObjectPerm) THEN;
  1004.  
  1005.         FailNil(aCloseWindowCommand);                    { just in case }
  1006.         aCloseWindowCommand.ICloseWindowCommand(cClose, SELF);
  1007.         PostCommand(aCloseWindowCommand);
  1008.         END;
  1009.     END;
  1010.  
  1011. {--------------------------------------------------------------------------------------------------}
  1012. {$S MASelCommand}
  1013.  
  1014. FUNCTION TWindow.HandleMouseDown(theMouse: VPoint;
  1015.                                  VAR info: EventInfo;
  1016.                                  VAR hysteresis: Point;
  1017.                                  VAR theCommand: TCommand): BOOLEAN; OVERRIDE;
  1018.  
  1019.     CONST
  1020.         systemEventMask     = app4Mask;                 { !!! defined as OSEvt in the MPW 3.1
  1021.                                                          interfaces }
  1022.  
  1023.     VAR
  1024.         wantsTheMouse:        BOOLEAN;
  1025.         anEvent:            EventRecord;
  1026.         aWMgrWindow:        WindowPtr;
  1027.         whereMouseDown:     integer;
  1028.  
  1029.     BEGIN
  1030.     theCommand := NIL;
  1031.     HandleMouseDown := TRUE;
  1032.  
  1033.     WITH info, thePEvent^ DO
  1034.         BEGIN
  1035.         whereMouseDown := FindWindow(where, aWMgrWindow);
  1036.  
  1037.         IF aWMgrWindow = fWMgrWindow THEN
  1038.             BEGIN
  1039.             CASE whereMouseDown OF
  1040.                 inContent:
  1041.                     BEGIN
  1042.                     wantsTheMouse := TRUE;
  1043.                     IF gApplication.GetActiveWindow <> SELF THEN
  1044.                         BEGIN
  1045.                         Select;
  1046.                         IF fDoFirstClick THEN
  1047.                         { Make sure this window is activated and updated }
  1048.                             gApplication.UpdateAllWindows
  1049.                         ELSE
  1050.                             wantsTheMouse := FALSE;
  1051.                         END;
  1052.  
  1053.                     IF wantsTheMouse THEN
  1054.                         HandleMouseDown := INHERITED HandleMouseDown(theMouse, info, hysteresis,
  1055.                                                                      theCommand)
  1056.                     ELSE
  1057.                         HandleMouseDown := FALSE;
  1058.                     END;
  1059.  
  1060.                 inDrag:
  1061.                     MoveByUser(where);
  1062.  
  1063.                 inGrow:
  1064.                     ResizeByUser(where);
  1065.  
  1066.                 inGoAway:
  1067.                     GoAwayByUser(where);
  1068.  
  1069.                 inZoomIn, inZoomOut:
  1070.                     ZoomByUser(where, whereMouseDown);
  1071.  
  1072.                 inDesk: ;
  1073.  
  1074.             END;
  1075.             END
  1076.         ELSE IF qDebug THEN
  1077.             ProgramBreak(
  1078.                      'in TWindow.HandleMouseDown: passed an event that didn''t belong to the window'
  1079.                          );
  1080.         END;
  1081.     END;
  1082.  
  1083. {--------------------------------------------------------------------------------------------------}
  1084. {$S MAWindowRes}
  1085.  
  1086. FUNCTION TWindow.HasPendingUpdate: BOOLEAN;
  1087.  
  1088.     BEGIN
  1089.     HasPendingUpdate := NOT EmptyRgn(WindowPeek(fWMgrWindow)^.updateRgn);
  1090.     END;
  1091.  
  1092. {--------------------------------------------------------------------------------------------------}
  1093. {$S MAOpen}
  1094.  
  1095. PROCEDURE TWindow.InstallDocument(itsDocument: TDocument);
  1096.  
  1097.     VAR
  1098.         aString:            Str255;
  1099.  
  1100.     BEGIN
  1101.     fDocument := itsDocument;
  1102.     IF itsDocument <> NIL THEN
  1103.         BEGIN
  1104.         gApplication.DeleteFreeWindow(SELF);            { Just in case… }
  1105.         itsDocument.AddWindow(SELF);
  1106.         aString := itsDocument.fTitle^^;                { SetTitleForDoc may move memory }
  1107.         IF aString <> '' THEN                            { not an untitled document }
  1108.             SetTitleForDoc(aString);
  1109.         fNextHandler := itsDocument;
  1110.         END
  1111.     ELSE
  1112.         BEGIN
  1113.         gApplication.AddFreeWindow(SELF);
  1114.         fNextHandler := gApplication;
  1115.         END;
  1116.     END;
  1117.  
  1118. {--------------------------------------------------------------------------------------------------}
  1119.  
  1120. FUNCTION PushLong(h, v: integer): LONGINT;
  1121. { This can be used to push a longint given a point.     PushLong(aPt.h,aPt.v); }
  1122.     INLINE $2E9F;                                        { MOVE.L (A7)+,(A7) }
  1123.  
  1124. {--------------------------------------------------------------------------------------------------}
  1125. {$S MANonRes}
  1126.  
  1127. FUNCTION TWindow.IsDraggable(whichRect: Rect): BOOLEAN;
  1128. { Returns TRUE if any of the corner points of whichRect are draggable. }
  1129.  
  1130.     VAR
  1131.         wDefProc:            Handle;
  1132.         variant:            integer;
  1133.         dontCare:            LONGINT;
  1134.         saveState:            SignedByte;
  1135.         rgnsWereBuilt:        BOOLEAN;
  1136.  
  1137.     BEGIN
  1138.     IsDraggable := TRUE;
  1139.     rgnsWereBuilt := BuildWindowRgns(kBuild);            { regions needed for hit testing }
  1140.     wDefProc := GetAndLoadWDefProc(WindowPeek(fWMgrWindow)^.windowDefProc);
  1141.     variant := GetWindowVariant(fWMgrWindow);
  1142.     saveState := GetHandleBits(wDefProc);
  1143.     LockHandleHigh(wDefProc);
  1144.  
  1145.     WITH whichRect DO                                    { is any corner pt in the drag region? }
  1146.         IF (CallWDefProc(variant, fWMgrWindow, wHit, PushLong(left, top), wDefProc) <> wInDrag) &
  1147.            (CallWDefProc(variant, fWMgrWindow, wHit, PushLong(right, bottom), wDefProc) <>
  1148.            wInDrag) & (CallWDefProc(variant, fWMgrWindow, wHit, PushLong(left, bottom),
  1149.            wDefProc) <> wInDrag) & (CallWDefProc(variant, fWMgrWindow, wHit, PushLong(right, top),
  1150.                                                   wDefProc) <> wInDrag) THEN
  1151.             IsDraggable := FALSE;                        { …no, so window _isn't_ draggable }
  1152.  
  1153.     SetHandleBits(wDefProc, saveState);
  1154.     IF BuildWindowRgns(rgnsWereBuilt) THEN;             { discard result }
  1155.     END;
  1156.  
  1157. {--------------------------------------------------------------------------------------------------}
  1158. {$S MANonRes}
  1159.  
  1160. FUNCTION TWindow.BuildWindowRgns(build: BOOLEAN): BOOLEAN;
  1161. { Calculate window size including structure region (i.e. title bar).  To do this
  1162.  we need to force the window to compute its structure region by calling its defproc,
  1163.  if the window isn't shown.
  1164.  IF build is FALSE, set the regions back to empty regions, so as not to confuse the
  1165.  window manager.
  1166.  Return the previous state of the regions. }
  1167.  
  1168.     VAR
  1169.         dontCare:            LONGINT;
  1170.         wDefProc:            Handle;
  1171.         topLeftInset, contDifference: Point;
  1172.         globalStrucRect, globalContRect: Rect;
  1173.         saveState:            SignedByte;
  1174.  
  1175.     BEGIN
  1176.     WITH WindowPeek(fWMgrWindow)^ DO
  1177.         BEGIN
  1178.         { The regions are considered to be built if either:
  1179.           a) the window is shown; or
  1180.           b) the structure rgn is not empty. }
  1181.         IF IsShown | NOT EmptyRgn(strucRgn) THEN
  1182.             BEGIN
  1183.             BuildWindowRgns := kBuild;
  1184.             IF (build <> kBuild) & NOT IsShown THEN
  1185.                 BEGIN
  1186.                 SetEmptyRgn(strucRgn);
  1187.                 SetEmptyRgn(contRgn);
  1188.                 END;
  1189.             END
  1190.         ELSE
  1191.             BEGIN
  1192.             BuildWindowRgns := NOT kBuild;
  1193.             IF (build = kBuild) THEN
  1194.                 BEGIN
  1195.                 wDefProc := GetAndLoadWDefProc(windowDefProc);
  1196.                 saveState := GetHandleBits(wDefProc);
  1197.                 LockHandleHigh(wDefProc);
  1198.                 dontCare := CallWDefProc(GetWindowVariant(fWMgrWindow), fWMgrWindow, wCalcRgns, 0,
  1199.                                          wDefProc);
  1200.                 SetHandleBits(wDefProc, saveState);
  1201.  
  1202.                 { Calculate offset from top-left of window structure to top-left of window content}
  1203.                 topLeftInset := contRgn^^.rgnBBox.topleft;
  1204.                 SubPt(strucRgn^^.rgnBBox.topleft, topLeftInset);
  1205.                 fContRgnInset := topLeftInset;
  1206.                 globalStrucRect := WindowPeek(fWMgrWindow)^.strucRgn^^.rgnBBox;
  1207.                 globalContRect := WindowPeek(fWMgrWindow)^.contRgn^^.rgnBBox;
  1208.                 contDifference.v := (globalStrucRect.bottom - globalStrucRect.top) -
  1209.                                     (globalContRect.bottom - globalContRect.top);
  1210.                 contDifference.h := (globalStrucRect.right - globalStrucRect.left) -
  1211.                                     (globalContRect.right - globalContRect.left);
  1212.                 fContDifference := contDifference;
  1213.                 END;
  1214.             END;
  1215.         END;
  1216.     END;
  1217.  
  1218. {--------------------------------------------------------------------------------------------------}
  1219. {$S MAWindowRes}
  1220.  
  1221. FUNCTION TWindow.IsShown: BOOLEAN; OVERRIDE;
  1222.  
  1223.     BEGIN
  1224.     IF fWMgrWindow <> NIL THEN
  1225.         IsShown := Ord(WindowPeek(fWMgrWindow)^.visible) <> 0
  1226.     ELSE
  1227.         IsShown := FALSE;
  1228.     END;
  1229.  
  1230. {--------------------------------------------------------------------------------------------------}
  1231. {$S MAWindowRes}
  1232.  
  1233. PROCEDURE TWindow.Locate(h, v: VCoordinate;
  1234.                          invalidate: BOOLEAN); OVERRIDE;
  1235.     VAR
  1236.         currLoc: Point;
  1237.  
  1238.     BEGIN
  1239.  
  1240.     INHERITED Locate(h, v, invalidate);
  1241.  
  1242.     IF fWMgrWindow <> NIL THEN
  1243.         BEGIN
  1244.         currLoc := fWMgrWindow^.portRect.topleft;
  1245.         LocalToGlobal(currLoc);
  1246.         IF (h <> currLoc.h) | (v <> currLoc.v) THEN
  1247.             MoveWindow(fWMgrWindow, h, v, FALSE);        { ??? should offset by fContRgnInset.v }
  1248.         END;
  1249.     IF (fIsActive | fDoFirstClick) & IsShown THEN
  1250.         gApplication.InvalidateCursorRgn;                {??? should this be a view method? }
  1251.     END;
  1252.  
  1253. {--------------------------------------------------------------------------------------------------}
  1254. {$S MAWindowRes}
  1255.  
  1256. PROCEDURE TWindow.Select;
  1257.  
  1258.     BEGIN
  1259.     gApplication.SelectWMgrWindow(fWMgrWindow);
  1260.     END;
  1261.  
  1262. {--------------------------------------------------------------------------------------------------}
  1263. {$S MAWindowRes}
  1264.  
  1265. PROCEDURE TWindow.MoveByUser(globalMouse: Point);
  1266.  
  1267.     VAR
  1268.         boundsRect:         Rect;
  1269.         currLoc:            Point;
  1270.  
  1271.     BEGIN
  1272.     boundsRect := fMoveBounds;
  1273.     DragWindow(fWMgrWindow, globalMouse, boundsRect);
  1274.     gLastUpTime := TickCount;                            { needed for double clicking the title bar,
  1275.                                                          because DragWindow eats the mouseUpEvent }
  1276.  
  1277.     { Don't forget to tell the window object }
  1278.     currLoc := fWMgrWindow^.portRect.topLeft;
  1279.     LocalToGlobal(currLoc);
  1280.     Locate(currLoc.h, currLoc.v, kDontInvalidate);
  1281.     END;
  1282.  
  1283. {--------------------------------------------------------------------------------------------------}
  1284. {$S MAOpen}
  1285.  
  1286. PROCEDURE TWindow.Open; OVERRIDE;
  1287.  
  1288.     BEGIN
  1289.     IF NOT IsShown THEN
  1290.         BEGIN
  1291.         { Keep us matching the window since we are parallel structures }
  1292.         WITH fWMgrWindow^.portRect DO
  1293.             Resize(right - left, bottom - top, kDontInvalidate);    { Be sure all views are sized right }
  1294.  
  1295.         AdjustSize;                                     { Give non-template views a shot at
  1296.                                                          correcting for sizedeterminers }
  1297.  
  1298.         IF fMustAdapt & NOT fAdapted THEN
  1299.             AdaptToScreen;
  1300.         IF (fMustHorzCenter & NOT fHorzCentered) | (fMustVertCenter & NOT fVertCentered) THEN
  1301.             Center(fMustHorzCenter, fMustVertCenter, fIsModal);
  1302.         IF fMustStagger & NOT fStaggered THEN
  1303.             BEGIN
  1304.             { If both staggering and forcing on screen are specified then we must ensure
  1305.             that the window is forced on screen FIRST so that the staggering will occur
  1306.             in a visible (and usable) location.  BUT, after staggering we must STILL ensure
  1307.             that the window is forced on screen so, we reset the forced flag so that
  1308.             forcing will occur on schedule later. }
  1309.             IF fMustForceOnScreen & NOT fForcedOnScreen THEN
  1310.                 BEGIN
  1311.                 ForceOnScreen;
  1312.                 fForcedOnScreen := FALSE;                { Make sure we can be forced again }
  1313.                 END;
  1314.             SimpleStagger(kStdStaggerAmount, kStdStaggerAmount, gStdStaggerCount);
  1315.             END;
  1316.         IF fMustForceOnScreen & NOT fForcedOnScreen THEN
  1317.             ForceOnScreen;
  1318.  
  1319.         Show(TRUE, kRedraw);                            { Make me visible }
  1320.  
  1321.         END;
  1322.     INHERITED Open;                                     { Tell subviews to open in case they care }
  1323.     END;
  1324.  
  1325. {--------------------------------------------------------------------------------------------------}
  1326. {$S MANonRes}
  1327.  
  1328. PROCEDURE TWindow.Resize(width, height: VCoordinate;
  1329.                          invalidate: BOOLEAN); OVERRIDE;
  1330.  
  1331.     VAR
  1332.         r:                    Rect;
  1333.  
  1334.     BEGIN
  1335.     IF (width <> fSize.h) | (height <> fSize.v) THEN
  1336.         BEGIN
  1337.         SizeWindow(fWMgrWindow, width, height, invalidate);
  1338.         InvalidateFocus;
  1339.  
  1340.         IF fIsResizable & invalidate & Focus THEN
  1341.             BEGIN
  1342.  
  1343.             SetRect(r, - kSBarSizeMinus1, - kSBarSizeMinus1, 0, 0);
  1344.  
  1345.             OffsetRect(r, fSize.h, fSize.v);
  1346.             InvalidRect(r);
  1347.  
  1348.             OffsetRect(r, width - fSize.h, height - fSize.v);
  1349.             InvalidRect(r);
  1350.             END;
  1351.  
  1352.         INHERITED Resize(width, height, invalidate);
  1353.  
  1354.         IF (fIsActive | fDoFirstClick) & IsShown THEN
  1355.             gApplication.InvalidateCursorRgn;
  1356.         END;
  1357.     END;
  1358.  
  1359. {--------------------------------------------------------------------------------------------------}
  1360. {$S MANonRes}
  1361.  
  1362. PROCEDURE TWindow.ResizeByUser(globalMouse: Point);
  1363.  
  1364.     VAR
  1365.         growResult:         LONGINT;
  1366.         resizeLimits:        Rect;
  1367.  
  1368.     BEGIN
  1369.     IF fIsResizable THEN
  1370.         BEGIN
  1371.         resizeLimits := fResizeLimits;                    { GrowWindow may move SELF }
  1372.         growResult := GrowWindow(fWMgrWindow, globalMouse, resizeLimits);
  1373.         IF growResult <> 0 THEN
  1374.             Resize(LoWrd(growResult), HiWrd(growResult), kInvalidate);
  1375.         IF (fIsActive | fDoFirstClick) & IsShown THEN
  1376.             gApplication.InvalidateCursorRgn;
  1377.         END;
  1378.     END;
  1379.  
  1380. {--------------------------------------------------------------------------------------------------}
  1381. {$S MAOpen}
  1382.  
  1383. PROCEDURE TWindow.SetResizeLimits(itsMinSize, itsMaxSize: Point);
  1384.  
  1385.     TYPE
  1386.         WStateDataPtr        = ^WStateData;
  1387.         WStateDataHandle    = ^WStateDataPtr;
  1388.  
  1389.     BEGIN
  1390.     fResizeLimits.topleft := itsMinSize;
  1391.     fResizeLimits.botRight := itsMaxSize;
  1392.  
  1393.     { If the window is zoomable, keep the window's state data current }
  1394.     IF BAND(fProcID, zoomDocProc) <> 0 THEN
  1395.         WITH WStateDataHandle(WindowPeek(fWMgrWindow)^.DataHandle)^^.stdState DO
  1396.             BEGIN
  1397.             right := Min(right, fLocation.h + itsMaxSize.h - 1);
  1398.             bottom := Min(bottom, fLocation.v + itsMaxSize.v - 1);
  1399.             END;
  1400.     END;
  1401.  
  1402. {--------------------------------------------------------------------------------------------------}
  1403. {$S MAWindowRes}
  1404.  
  1405. PROCEDURE TWindow.SetTarget(newTarget: TEvtHandler);
  1406.  
  1407.     BEGIN
  1408.     IF newTarget = NIL THEN                             { Would be annoying if a nil got in here! }
  1409.         newTarget := SELF;
  1410.  
  1411.     fTarget := newTarget;
  1412.     IF gApplication.GetActiveWindow = SELF THEN
  1413.         gApplication.SetTarget(newTarget);
  1414.     END;
  1415.  
  1416. {--------------------------------------------------------------------------------------------------}
  1417. {$S MAWindowRes}
  1418.  
  1419. PROCEDURE TWindow.SetTitle(newTitle: Str255);
  1420.  
  1421.     VAR
  1422.         oldTitle:            Str255;
  1423.  
  1424.     BEGIN
  1425.     GetWTitle(fWMgrWindow, oldTitle);                    { to minimize flash, we only set the title
  1426.                                                          if it's different from the current title }
  1427.     IF CompareStrings(oldTitle, newTitle) <> sortsEqual THEN
  1428.         SetWTitle(fWMgrWindow, newTitle);
  1429.     END;
  1430.  
  1431. {--------------------------------------------------------------------------------------------------}
  1432. {$S MAFile}
  1433.  
  1434. PROCEDURE TWindow.SetTitleForDoc(newDocTitle: Str255);
  1435.  
  1436.     VAR
  1437.         title:                Str255;
  1438.  
  1439.     BEGIN
  1440.     IF fPreDocname > 0 THEN                             { optimize for case of nothing to do }
  1441.         BEGIN
  1442.         GetTitle(title);
  1443.  
  1444.         IF SubstituteInTitle(title, newDocTitle, fPreDocname, fConstTitle) THEN
  1445.             SetTitle(title);
  1446.         END;
  1447.     END;
  1448.  
  1449. {--------------------------------------------------------------------------------------------------}
  1450. {$S MANonRes}
  1451.  
  1452. PROCEDURE TWindow.Show(state, redraw: BOOLEAN); OVERRIDE;
  1453.  
  1454.     BEGIN
  1455.     IF (fWMgrWindow <> NIL) & redraw THEN
  1456.         IF (fIsActive | fDoFirstClick) THEN
  1457.             gApplication.InvalidateCursorRgn;
  1458.     IF state THEN
  1459.         BEGIN
  1460.         WITH fWMgrWindow^.portRect DO
  1461.             Resize(right - left, bottom - top, redraw);    { Be sure all views are sized right }
  1462.         ShowWindow(fWMgrWindow);
  1463.         END
  1464.     ELSE
  1465.         BEGIN
  1466.         HideWindow(fWMgrWindow);
  1467.         END;
  1468.  
  1469.     INHERITED Show(state, redraw);
  1470.     END;
  1471.  
  1472. {--------------------------------------------------------------------------------------------------}
  1473. {$S MAOpen}
  1474.  
  1475. PROCEDURE TWindow.SimpleStagger(dh, dv: integer;
  1476.                                 VAR counter: integer);
  1477.  
  1478.     VAR
  1479.         globalRect:         Rect;                        { The topLeft of the window must fall in
  1480.                                                          here. }
  1481.         Pt:                 Point;
  1482.         nSlots:             integer;
  1483.         slot:                integer;
  1484.  
  1485.     BEGIN
  1486.     fStaggered := TRUE;
  1487.     { Get window rect, which gives us globalRect.topLeft & size of window }
  1488.     GetGlobalBounds(globalRect);
  1489.  
  1490.     { Compute globalRect.botRight = globalRect.topleft + <bounds botRight> - <window botRight> }
  1491.     Pt := globalRect.topleft;
  1492.     AddPt(fMoveBounds.botRight, Pt);
  1493.     SubPt(globalRect.botRight, Pt);
  1494.     globalRect.botRight := Pt;
  1495.  
  1496.         { This covers the case of dh & dv both >= 0; if either is less than
  1497.         0, the right (bottom) limit is set to the left (top) edge of the
  1498.         screen -- allowing for some margin.  This makes the right (bottom)
  1499.         edge less than the left (top) edge, but this is OK since the DIV
  1500.         statement below will be dividing 2 negative numbers. }
  1501.  
  1502.     IF dh < 0 THEN
  1503.         globalRect.right := fMoveBounds.left;
  1504.     IF dv < 0 THEN
  1505.         globalRect.bottom := fMoveBounds.top;
  1506.  
  1507.     { This code avoids divide by zero problems }
  1508.     IF (dh = 0) | (dv = 0) THEN
  1509.         nSlots := 0
  1510.     ELSE
  1511.         nSlots := Min((globalRect.right - globalRect.left + dh - 1) DIV dh, (globalRect.bottom -
  1512.                       globalRect.top + dv - 1) DIV dv);
  1513.     IF nSlots = 0 THEN
  1514.         slot := 0
  1515.     ELSE
  1516.         slot := counter MOD nSlots;
  1517.  
  1518.     IF slot <> 0 THEN                                    { move the window }
  1519.         BEGIN
  1520.         { pt ends up as the place to position the window }
  1521.         Pt := globalRect.topleft;
  1522.  
  1523.         Pt.h := Pt.h + (slot * dh);
  1524.         Pt.v := Pt.v + (slot * dv);
  1525.  
  1526.         Locate(Pt.h, Pt.v, kDontInvalidate);
  1527.         END;
  1528.  
  1529.     counter := counter + 1;
  1530.     END;
  1531.  
  1532. {--------------------------------------------------------------------------------------------------}
  1533. {$S MAWindowRes}
  1534.  
  1535. PROCEDURE TWindow.Update; OVERRIDE;
  1536.  
  1537.     VAR
  1538.         fi:                 FailInfo;
  1539.  
  1540.     PROCEDURE HdlUpdate(error: OSErr;
  1541.                         message: LONGINT);
  1542.  
  1543.         BEGIN
  1544.         EndUpdate(fWMgrWindow);                         { Need to balance the BeginUpdate }
  1545.         { Or we get into an infinite loop }
  1546.         { trying to update the window when }
  1547.         { displaying an alert }
  1548.         InvalidateFocus;
  1549.         END;
  1550.  
  1551.     BEGIN
  1552.     IF HasPendingUpdate THEN
  1553.         BEGIN
  1554.         InvalidateFocus;
  1555.         BeginUpdate(fWMgrWindow);
  1556.  
  1557.         CatchFailures(fi, HdlUpdate);
  1558.         DrawContents;
  1559.         Success(fi);
  1560.  
  1561.         EndUpdate(fWMgrWindow);
  1562.         InvalidateFocus;
  1563.         END;
  1564.     END;
  1565.  
  1566. {--------------------------------------------------------------------------------------------------}
  1567. {$S MANonRes}
  1568.  
  1569. PROCEDURE TWindow.Zoom(partCode: integer);
  1570.  
  1571.     VAR
  1572.         aGDScreenRect:        Rect;
  1573.  
  1574.     PROCEDURE CalcZoomRect(forScreenRect: Rect);
  1575.  
  1576.         CONST
  1577.             edge                = 2;                    { leave space around window structure area,
  1578.                                                          ??? settable?}
  1579.  
  1580.         TYPE
  1581.             WStateDataPtr        = ^WStateData;
  1582.             WStateDataHandle    = ^WStateDataPtr;
  1583.  
  1584.         VAR
  1585.             zoomRect:            Rect;
  1586.             width, height:        integer;
  1587.  
  1588.         BEGIN
  1589.         InsetRect(forScreenRect, edge, edge);
  1590.         WITH forScreenRect DO
  1591.             BEGIN
  1592.             { calculate the maximum structure size }
  1593.             width := Min((right - left), fResizeLimits.botRight.h + fContDifference.h);
  1594.             height := Min((bottom - top), fResizeLimits.botRight.v + fContDifference.v);
  1595.  
  1596.             zoomRect.top := top + fContRgnInset.v + ((bottom - top) - height) DIV 2;
  1597.             zoomRect.left := left + fContRgnInset.h + ((right - left) - width) DIV 2;
  1598.             zoomRect.right := zoomRect.left + width - fContDifference.h + 1;
  1599.             zoomRect.bottom := zoomRect.top + height - fContDifference.v + 1;
  1600.  
  1601.             END;
  1602.  
  1603.         IF BAND(fProcID, zoomDocProc) <> 0 THEN
  1604.             WStateDataHandle(WindowPeek(fWMgrWindow)^.DataHandle)^^.stdState := zoomRect; { new
  1605.             zoom-out rect }
  1606.         END;
  1607.  
  1608.     BEGIN
  1609.     IF (qNeedsColorQD | gConfiguration.hasColorQD) & (partCode = inZoomOut) THEN { support multiple
  1610.            screens }
  1611.         BEGIN
  1612.         IF (GetMaxIntersectedDevice(aGDScreenRect) = NIL) THEN; { dont care about result }
  1613.         CalcZoomRect(aGDScreenRect);
  1614.         END;
  1615.  
  1616.     IF Focus THEN                                        { ??? (still true?) The ROM has a bug
  1617.                                                          requiring that thePort be the window being
  1618.                                                          zoomed. }
  1619.         BEGIN
  1620.         EraseRect(thePort^.portRect);                    { Erasing was suggested by Ernie B.; the
  1621.                                                          Finder does this. ??? is this _still_ a
  1622.                                                          good idea. Help stamp out flicker. }
  1623.         ZoomWindow(fWMgrWindow, partCode, FALSE);
  1624.  
  1625.         { let the View know what we've done }
  1626.         WITH fWMgrWindow^.portRect DO
  1627.             Resize(right - left, bottom - top, kInvalidate);
  1628.         END;
  1629.  
  1630.     IF (fIsActive | fDoFirstClick) & IsShown THEN
  1631.         gApplication.InvalidateCursorRgn;
  1632.     END;
  1633.  
  1634. {--------------------------------------------------------------------------------------------------}
  1635. {$S MANonRes}
  1636.  
  1637. PROCEDURE TWindow.ZoomByUser(globalMouse: Point;
  1638.                              partCode: integer);
  1639.  
  1640.     BEGIN
  1641.     IF TrackBox(fWMgrWindow, globalMouse, partCode) THEN
  1642.         Zoom(partCode);
  1643.     END;
  1644.  
  1645. {--------------------------------------------------------------------------------------------------}
  1646. {$S MAFields}
  1647.  
  1648. PROCEDURE TWindow.Fields(PROCEDURE DoToField(fieldName: Str255;
  1649.                                              fieldAddr: Ptr;
  1650.                                              fieldType: integer)); OVERRIDE;
  1651.  
  1652.     VAR
  1653.         theFlag:            BOOLEAN;
  1654.  
  1655.     BEGIN
  1656.     DoToField('TWindow', NIL, bClass);
  1657.     DoToField('fWMgrWindow', @fWMgrWindow, bWindowPtr);
  1658.     DoToField('fProcID', @fProcID, bInteger);
  1659.     DoToField('fMoveBounds', @fMoveBounds, bRect);
  1660.     DoToField('fResizeLimits', @fResizeLimits, bRect);
  1661.     DoToField('fTarget', @fTarget, bObject);
  1662.     DoToField('fTargetID', @fTargetID, bIDType);
  1663.     DoToField('fPreDocName', @fPreDocname, bInteger);
  1664.     DoToField('fConstTitle', @fConstTitle, bInteger);
  1665.     DoToField('fMustAdapt', @fMustAdapt, bBoolean);
  1666.     DoToField('fMustHorzCenter', @fMustHorzCenter, bBoolean);
  1667.     DoToField('fMustVertCenter', @fMustVertCenter, bBoolean);
  1668.     DoToField('fMustStagger', @fMustStagger, bBoolean);
  1669.     DoToField('fMustForceOnScreen', @fMustForceOnScreen, bBoolean);
  1670.     DoToField('fAdapted', @fAdapted, bBoolean);
  1671.     DoToField('fHorzCentered', @fHorzCentered, bBoolean);
  1672.     DoToField('fVertCentered', @fVertCentered, bBoolean);
  1673.     DoToField('fStaggered', @fStaggered, bBoolean);
  1674.     DoToField('fForcedOnScreen', @fForcedOnScreen, bBoolean);
  1675.     DoToField('fIsActive', @fIsActive, bBoolean);
  1676.     DoToField('fIsResizable', @fIsResizable, bBoolean);
  1677.     DoToField('fIsClosable', @fIsClosable, bBoolean);
  1678.     DoToField('fFreeOnClosing', @fFreeOnClosing, bBoolean);
  1679.     DoToField('fDisposeOnFree', @fDisposeOnFree, bBoolean);
  1680.     DoToField('fClosesDocument', @fClosesDocument, bBoolean);
  1681.     DoToField('fOpenInitially', @fOpenInitially, bBoolean);
  1682.     DoToField('fIsModal', @fIsModal, bBoolean);
  1683.     DoToField('fDoFirstClick', @fDoFirstClick, bBoolean);
  1684.     DoToField('fFloats', @fFloats, bBoolean);
  1685.     DoToField('fContRgnInset', @fContRgnInset, bPoint);
  1686.     DoToField('fContDifference', @fContDifference, bPoint);
  1687.     INHERITED Fields(DoToField);
  1688.     END;
  1689.